import { AxesHelper, Camera, Color, Object3D, PerspectiveCamera, Scene, WebGLRenderer } from "three";
import { OrbitControls } from "three/examples/jsm/Addons.js";
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { getMaxTextures } from "../helper/GLHelper";

export class Base {
  scene: Scene;
  camera: Camera;
  renderer: WebGLRenderer;
  orbitControls: OrbitControls;
  container: HTMLElement;
  stats: Stats;
  initCreateObjects: Object3D[] = [];

  renderCallBackFns: Function[] = [];

  // 扩展： 添加composer后期渲染属性？ 参考kokomi.js 的 base.js

  constructor(container: HTMLElement) {
    this.container = container;

    // scene
    const scene = new Scene();
    scene.background = new Color(0xeeeeee);
    const width = container.offsetWidth;
    const height = container.offsetHeight;
    this.scene = scene;

    // camera
    const camera = new PerspectiveCamera(45, width / height, 0.1, 5000);
    camera.position.set(0,0,50);
    this.camera = camera;

    // renderer
    const renderer = new WebGLRenderer({
      antialias: true,
    });
    renderer.setSize(width, height); // 设置渲染器（canvas）的尺寸
    this.renderer = renderer;

    // controls
    const orbitControls = new OrbitControls(camera, renderer.domElement);
    this.orbitControls = orbitControls;

    // init objects
    const axesHelper = new AxesHelper(2000);
    scene.add(axesHelper);

    this.initCreateObjects.push(axesHelper);

    // 将renderer的canvas添加到容器
    container.appendChild(renderer.domElement);

    // status
    const stats = new Stats();
    stats.showPanel(0); // 1 显示 GPU 时间
    // 设置监视器位置
    stats.dom.style.position = "absolute";
    stats.dom.style.left = "0px";
    stats.dom.style.top = "0px";
    document.body.appendChild(stats.dom);
    this.stats = stats;

    getMaxTextures(renderer);

    // container 监听

    // container.addEventListener("mousemove", (e) => {
    //   this.render();
    // });

    this.renderAuto();
  }

  renderAuto() {
    this.render();
    requestAnimationFrame(this.renderAuto.bind(this));
  }

  render() {
    this.stats.begin();
    this.renderer.render(this.scene, this.camera);
    this.renderCallback();

    this.stats.end();
  }

  addRenderCallback(fn: Function) {
    this.renderCallBackFns.push(fn);
  }

  private renderCallback() {
    this.renderCallBackFns.forEach(fn => fn());
  }

}
